//
// Created by hrg on 2019/12/2.
//

#ifndef ECDRIVER_DEVICE_H
#define ECDRIVER_DEVICE_H

#include <boost/function.hpp>
#include <boost/thread.hpp>

#include <native/task.h>

#include <ecdata.h>
#include <slave.h>
#include <master.h>
#include <config.h>
#include <list.h>

#include <vector>
#include <list>
#include <map>

class Device{
typedef boost::function<Target(EcStatus&)> UpdateTargetHandle;
typedef boost::function<void(EcStatus&)> UpdateStatusHandle;
public:
    Device(EcData* ecData = nullptr, int master = 0);
    ~Device();

    bool Init(ulong period, ulong offset_, int8_t mode, std::string xmldir);
    bool Config();

    void SetSlaveMode(int index, int mode);
    int8_t GetAllStatus();
    int8_t GetOneStatus(int index);
    void SetCurstomInterface(UpdateTargetHandle handle)
    {
        update_handle_ = handle;
    }

    void AddStatusHandle(UpdateStatusHandle handle)
    {
        status_handle_.push_back(handle);
    }

    EcType GetSlvType(int index);
    uint16_t GetErrorCode(int index);
    EcStatus& GetEcStatus();
    /**
     * @Func
     *      GetServoNum
     * @Berif
     *      get the number of slave
     * @Input
     *      none
     * @Output
     *      return the number of slave
     */
    size_t GetServoNum();
    size_t GetEcIONum();

    int* GetCurrPos();
    int* GetCurrVel();

    int* GetTargetVel();
    int* GetTargetPos();

    /**
     * @Func
     *      SetIOCmd
     * @Berif
     *      设置IO命令
     * @Input
     *      index: IO模块对应的索引号
     *      cmd  : 下发给IO模块的命令
     * @Output
     *      成功，返回true; 失败，返回false
    */
    bool SetIOCmd(int index, int cmd);
#if 0
    uint32_t GetIOCmd(int index);
#endif
    uint32_t GetIOAna(int index, int pdo);
    uint32_t GetIODig(int index);

    /**
     * @Func
     *      EnableSlaves
     * @Berif
     *      enable index slave
     * @Input
     *      index: the index of slave
     * @Output
     *      success, return true; or, return false
     */
    bool EnableSlaves(int index);
    bool DisableSlaves(int index);
    bool IsEnableSlaveCheck(int index);

    /**
     * @Func
     *      StartRTask
     * @Berif
     *      start rt task
     * @Input
     *      none
     * @Output
     *      success, return true; or, return false
     */
    bool StartRTask();
    bool StopRTask();

    void ClearDataCache();
    void Reset(int index);

    friend void DeviceRTask(void* argv);
protected:

    /**
     * @Func
     *      UpDataPos
     * @Berif
     *      flush the target postion to slave
     * @Input
     *      none
     * @Output
     *      success, return true; or, return false
     */
    bool UpDataPos();
    void UpdatePos(Target target);

    /**
     * @Func
     *      CheckSlvStatus
     * @Berif
     *      Check all slave status
     * @Input
     *      none
     * @Output
     */
    int8_t CheckSlvStatus();

    void RunRTask();
#ifdef DELAY
    static void SetTaskDelay();
#endif

private:
    RT_TASK rtask_;

    int slvnums_;
    int dataPos_;
    ulong period_;
    ulong offset_;
    int mode_;

    int* currpos_;    // 实时位置
    int* currvel_;    // 实际速度

    int* targetpos_;  // 目标位置
    int* targetvel_;  // 目标速度
    int* currptr_;

    Master *master_;
    int masterid_;

    std::map<int, SlavePtr> servos_;
    std::map<int, SlavePtr> ecios_;

    List<EcStatus> ec_status_list_;
    std::list<UpdateStatusHandle> status_handle_;
    UpdateTargetHandle update_handle_;

    EcStatus ecstatus_;

    std::list<double> clockdelay_;
    int clocknum_;

    bool stoptask_;
    bool starttask_;
    bool linkstatus_;
    bool switchon_;

    uint8_t *domainptr_;
    int8_t onstatus_;

    EcData *ecdata_;
    EcXml m_Ecxml_;

};
#endif //ECDRIVER_DEVICE_H
